package panicsafe

import (
	"runtime/debug"
)

var (
	GoFunCatchException bool = true
	OnCatchAllPanic     func(err interface{}, args ...interface{})

	// 处理输出的stacks
	onProcessPanicStackFunc = func(stacks []byte) []byte {
		return stacks
	}
)

//func GetCallStacks(skipCalls int) string {
//	return string(debug.Stack())
//}

// GetCallStacks 保留第一行goroutine信息，跳过指定次数的调用（每次调用对应2行）
// 优化点：单次循环完成定位，直接截取原始字节切片，无额外内存分配
func GetCallStacks(skip int) []byte {
	stack := debug.Stack()
	if len(stack) == 0 {
		return stack
	}

	skip += 2

	// 目标：保留[0, firstLineEnd] + [cutStart, len(stack)]
	var (
		firstLineEnd int        // 第一行结束索引（包含换行符）
		cutStart     int        // 跳过指定行后的起始索引
		state        int        // 0:寻找第一行结束 1:计数跳过的行
		newlineCount int        // 已跳过的行数（在state=1时有效）
		linesToSkip  = skip * 2 // 需要跳过的总行数
	)

	// 单次循环完成所有定位
	for i, b := range stack {
		if b != '\n' {
			continue
		}

		switch state {
		case 0:
			// 找到第一行结束位置
			firstLineEnd = i
			state = 1
			// 如果不需要跳过任何行，直接确定切割点
			if linesToSkip == 0 {
				cutStart = i + 1
				break
			}
		case 1:
			// 计数跳过的行
			newlineCount++
			if newlineCount == linesToSkip {
				cutStart = i + 1
				break // 找到目标后提前退出循环
			}
		}
	}

	// 处理边界情况
	switch {
	case cutStart == 0:
		// 未找到足够的行可跳过，仅返回第一行
		stack = stack[:firstLineEnd+1]
	default:
		// 拼接第一行和剩余有效部分（通过切片实现，无额外分配）
		stack = append(stack[:firstLineEnd+1], stack[cutStart:]...)
	}

	return onProcessPanicStackFunc(stack)
}

func ProcessStacks(stacks []byte) []byte {
	return onProcessPanicStackFunc(stacks)
}

func DeferCatchPanic(args ...interface{}) {
	if err := recover(); err != nil {
		if OnCatchAllPanic != nil {
			OnCatchAllPanic(err, args...)
		}
	}
}

func SetProcessPanicStackFunc(fn func(stacks []byte) []byte) {
	if fn == nil {
		fn = func(stacks []byte) []byte {
			return stacks
		}
	}
	onProcessPanicStackFunc = fn
}

// 推荐这种方式，stack()，可以追寻的go的掉用处,
func GoRun(fn func()) {
	if GoFunCatchException {
		defer DeferCatchPanic()
	}
	fn()
}
